﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;

namespace SqliteManager
{
    public static class Extension
    {
        public static T FirstEx<T>(this T[] arr, Func<T, bool> predicate)
        {
            for(int i =0;i<arr.Length;i++)
            {
                if(predicate(arr[i]))
                {
                    return arr[i];
                }
            }

            return default(T);
        }

        /// <summary>
        /// 将字符串转换为系统对象
        /// </summary>
        /// <param name="str"></param>
        /// <param name="objtype"></param>
        /// <returns></returns>
        public static object StringToSystemObjectType(this string str,Type objtype)
        {
            return __StringToSystemObjectType(str, objtype);
        }

        /// <summary>
        /// 判断是否是系统层面的类型（CTS）
        /// </summary>
        /// <param name="str"></param>
        /// <param name="objtype"></param>
        /// <returns></returns>
        private static object __StringToSystemObjectType(string str, Type objtype)
        {
            switch (Type.GetTypeCode(objtype))
            {
                case TypeCode.Int32:
                    return Convert.ToInt32(str);
                case TypeCode.Int64:
                    return Convert.ToInt64(str);
                case TypeCode.Single:
                    return Convert.ToSingle(str);
                case TypeCode.Boolean:
                    return Convert.ToBoolean(str);
                case TypeCode.String:
                    return str;
            }

            return str;
        }

        /// <summary>
        /// 将字符串转换成单一对象（不包括列表和数组等）
        /// </summary>
        /// <param name="str"></param>
        /// <param name="objtype"></param>
        /// <param name="isSetFields"></param>
        /// <returns></returns>
        private static object StringToObjectType(string str, Type objtype, bool isSetFields = false)
        {
            //作为Object处理
            string[] Properties = str.Split(',');
            int PropertiesCount = Properties.Length;

            if (PropertiesCount <= 0)
            {
                Properties = new string[] { str };
                PropertiesCount = Properties.Length;
            }

            object newobj = null;
            newobj = Activator.CreateInstance(objtype);
            string[] pair = null;
            foreach (string onepair in Properties)
            {
                pair = onepair.Split('=');
                if (pair == null || pair.Length < 2)
                {
                    continue;
                }

                PropertyInfo pi = objtype.GetProperty(pair[0]);
                if (pi != null)
                {
                    pi.SetValue(newobj, pair[1].FromDataString(pi.PropertyType, isSetFields), null);
                }

                //判断是否是Struct或者开启了字段设置isSetFields（作为Struct时若未开启字段设置且属性为0时将强制设置字段）
                bool isStruct = !objtype.IsClass && PropertiesCount <= 0;
                if (isSetFields || isStruct)
                {
                    FieldInfo fi = objtype.GetField(pair[0]);
                    if (fi != null)
                    {
                        fi.SetValue(newobj, pair[1].FromDataString(fi.FieldType, isSetFields));
                    }
                }
            }
            return newobj;
        }

        /// <summary>
        /// 将字符串转换成List或Dictionary
        /// </summary>
        /// <param name="str"></param>
        /// <param name="objtype"></param>
        /// <param name="isSetFields"></param>
        /// <returns></returns>
        private static object StringToGenricType(string str, Type objtype, bool isSetFields = false)
        {

            string[] AllItem = str.Split(';');

            int ItemCount = AllItem.Length;

            if (ItemCount <= 0)
            {
                AllItem = new string[] { str };
                ItemCount = AllItem.Length;
            }

            object newobj = null;

            MethodInfo mi = objtype.GetMethod("Add");

            Type[] tp = objtype.GetGenericArguments();

            Type concreteListType = null;
            Type listItemType = null;

            bool IsDictionary = tp.Length > 1 ? true : false;

            object[] paramsAddItem = null;

            if (IsDictionary)
            {
                listItemType = tp[1];
                concreteListType = typeof(Dictionary<,>).MakeGenericType(tp[0], listItemType);
                paramsAddItem = new object[2] { new object(), new object() };
            }
            else
            {
                listItemType = tp[0];
                concreteListType = typeof(List<>).MakeGenericType(listItemType);
                paramsAddItem = new object[1] { new object() };
            }

            newobj = Activator.CreateInstance(concreteListType);

            object newItemObj = null;
            object key = null;
            string[] DictItems = null;
            for (int i = 0; i < ItemCount; i++)
            {
                if (IsDictionary)
                {
                    DictItems = AllItem[i].Split('|');
                    newItemObj = DictItems[1].FromDataString(listItemType, isSetFields);
                    key = DictItems.Length > 1 ? DictItems[0].FromDataString(tp[0]) : i.ToString().FromDataString(tp[0]);
                    paramsAddItem[0] = key;
                    paramsAddItem[1] = newItemObj;
                }
                else
                {
                    newItemObj = AllItem[i].FromDataString(listItemType, isSetFields);
                    paramsAddItem[0] = newItemObj;
                }
                mi.Invoke(newobj, paramsAddItem);
            }
            return newobj;
        }

        /// <summary>
        /// 将字符串转换成Array对象
        /// </summary>
        /// <param name="str"></param>
        /// <param name="objtype"></param>
        /// <param name="isSetFields"></param>
        /// <returns></returns>
        private static object StringToArrayType(string str, Type objtype, bool isSetFields = false)
        {
            string[] AllItem = str.Split(';');

            int ItemCount = AllItem.Length;

            if (ItemCount <= 0)
            {
                AllItem = new string[] { str };
                ItemCount = AllItem.Length;
            }

            Type listItemType = objtype.GetElementType();
            Array values = Array.CreateInstance(listItemType, ItemCount);

            for (int i = 0; i < ItemCount; i++)
            {
                object newItemObj = AllItem[i].FromDataString(listItemType, isSetFields);
                values.SetValue(newItemObj, i);
            }
            return values;
        }

        /// <summary>
        /// 将字符串转换为相应的对象或列表
        /// </summary>
        /// <param name="str"></param>
        /// <param name="objtype"></param>
        /// <param name="isSetFields"></param>
        /// <returns></returns>
        public static object FromDataString(this string str, Type objtype, bool isSetFields = false)
        {
            //是否系统层面的类型
            if (Type.GetTypeCode(objtype) != TypeCode.Object)
            {
                return __StringToSystemObjectType(str, objtype);
            }

            //是否是List或Dictionary
            if (objtype.IsGenericType)
            {
                return StringToGenricType(str, objtype, isSetFields);
            }

            //是否是Array
            if (objtype.IsArray)
            {
                return StringToArrayType(str, objtype, isSetFields);
            }

            return StringToObjectType(str, objtype, isSetFields);
        }

        /// <summary>
        /// 进行指定类型的转换
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="str"></param>
        /// <param name="isSetFields"></param>
        /// <returns></returns>
        public static T FromDataString<T>(this string str, bool isSetFields = false)
        {
            return (T)str.FromDataString(typeof(T), isSetFields);
        }

        /// <summary>
        /// 单一对象转换为字符串（不包括List，Dict和Array）
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="isShowFields"></param>
        /// <param name="isConvertChild"></param>
        /// <returns></returns>
        private static string ObjectTypeToDataString(object obj, bool isShowFields = true, bool isConvertChild = false)
        {
            //作为object对象

            string listItemformat = "";
            PropertyInfo[] listitempropertyinfos = obj.GetType().GetProperties();
            int itempropertyCount = listitempropertyinfos.Length;
            for (int j = 0; j < itempropertyCount; j++)
            {
                if (isConvertChild && Type.GetTypeCode(listitempropertyinfos[j].PropertyType) == TypeCode.Object)
                {
                    listItemformat += string.Format("{0}={{{1}}}", listitempropertyinfos[j].Name, listitempropertyinfos[j].GetValue(obj, null).ToDataString(isShowFields, isConvertChild));
                }
                else
                {
                    try
                    {
                        listItemformat += string.Format("{0}={1}", listitempropertyinfos[j].Name, listitempropertyinfos[j].GetValue(obj, null));
                    }
                    catch (Exception e)
                    {
                        listItemformat += string.Format("{0}={1}", listitempropertyinfos[j].Name, "Error:" + e.Message);
                    }
                }

                if (j < itempropertyCount - 1)
                {
                    listItemformat += ",";
                }
            }
            bool isStruct = !obj.GetType().IsClass && itempropertyCount <= 0;
            if (isShowFields || isStruct)
            {
                FieldInfo[] fieldInfos = obj.GetType().GetFields();
                int itemfieldinoCount = fieldInfos.Length;
                for (int j = 0; j < itemfieldinoCount; j++)
                {
                    if (isConvertChild && Type.GetTypeCode(fieldInfos[j].FieldType) == TypeCode.Object && !fieldInfos[j].FieldType.IsGenericType && !fieldInfos[j].FieldType.IsArray)
                    {
                        listItemformat += string.Format("{0}={{{1}}}", fieldInfos[j].Name, fieldInfos[j].GetValue(obj).ToDataString(isShowFields, isConvertChild));
                    }
                    else
                    {
                        listItemformat += string.Format("{0}={1}", fieldInfos[j].Name, fieldInfos[j].GetValue(obj).ToDataString(isShowFields, isConvertChild));
                    }
                    if (j < itemfieldinoCount - 1)
                    {
                        listItemformat += ",";
                    }
                }
            }
            return listItemformat;
        }

        /// <summary>
        /// 将对象序列化成字符串
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static string ToDataString(this object obj, bool isShowFields = true, bool isConvertChild = false)
        {
            string listItemformat = "";

            if (obj == null)
            {
                return null;
            }

            //作为系统层对象
            if (Type.GetTypeCode(obj.GetType()) != TypeCode.Object)
            {
                return obj.ToString();
            }

            //作为Array对象
            if (obj.GetType().IsArray)
            {
                Array array = obj as Array;
                int len = array.Length;

                if (isConvertChild)
                {
                    listItemformat += "[";
                }
                for (int i = 0; i < len; i++)
                {
                    object listItem = array.GetValue(i);
                    listItemformat += string.Format("{0}", listItem.ToDataString(isShowFields, isConvertChild));
                    if (i < len - 1)
                    {
                        listItemformat += ";";
                    }
                }
                if (isConvertChild)
                {
                    listItemformat += "]";
                }
                return listItemformat;
            }

            //作为Dictionary对象
            if (obj.GetType().IsGenericType && obj.GetType().GetGenericArguments().Length > 1)
            {
                IDictionary Dict = obj as IDictionary;
                string strKey = null;
                string strValue = null;
                int index = 0;
                int count = Dict.Count;
                if (isConvertChild)
                {
                    listItemformat += "[";
                }
                foreach (object key in Dict.Keys)
                {
                    strKey = key.ToDataString(isShowFields, isConvertChild);
                    strValue = Dict[key].ToDataString(isShowFields, isConvertChild);
                    listItemformat += string.Format("{0}|{1}", strKey, strValue);
                    index++;
                    if (index < count)
                    {
                        listItemformat += ";";
                    }
                }
                if (isConvertChild)
                {
                    listItemformat += "]";
                }

                return listItemformat;
            }

            //作为List对象
            if (obj.GetType().IsGenericType)
            {
                int listcount = Convert.ToInt32(obj.GetType().GetProperty("Count").GetValue(obj, null));
                if (isConvertChild)
                {
                    listItemformat += "[";
                }
                for (int i = 0; i < listcount; i++)
                {
                    object listItem = obj.GetType().GetProperty("Item").GetValue(obj, new object[] { i });
                    listItemformat += string.Format("{0}", listItem.ToDataString(isShowFields, isConvertChild));
                    if (i < listcount - 1)
                    {
                        listItemformat += ";";
                    }
                }
                if (isConvertChild)
                {
                    listItemformat += "]";
                }

                return listItemformat;
            }

            listItemformat += ObjectTypeToDataString(obj, isShowFields, isConvertChild);

            return listItemformat;
        }
    }
}
